/**
 * Copyright (C) 2012 LightAsyncHttpClient Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.oc.mba.http;

import java.io.IOException;

import javax.net.ssl.SSLHandshakeException;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpVersion;
import org.apache.http.NoHttpResponseException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;

/**
 * <ul>
 * <li><b>name : </b>		HttpSetting		</li>
 * <li><b>description :</b>	Http设置				</li>
 * <li><b>author : </b>		桥下一粒砂			</li>
 * <li><b>e-mail : </b>		chenyoca@gmail.com	</li>
 * <li><b>weibo : </b>		@桥下一粒砂			</li>
 * <li><b>date : </b>		2012-9-22 上午12:17:50		</li>
 * </ul>
 */
public class HttpClientSetting {

	/** 版本号 **/
	private static final String VERSION = "1.0";
	
	/** 默认最大连接数 **/
	private static final int DEF_MAX_CONNECTIONS = 10;

	/** 每个路由节点最大的连接数 **/
	private static final int DEF_MAX_CONNECTIONS_PER_ROUTE = 10;
	
	/** 默认Socket超时 **/
    private static final int DEF_SOCKET_TIMEOUT = 6 * 1000;
    
    /** 默认Socket缓冲区大小 **/
    private static final int DEF_SOCKET_BUFFER_SIZE = 8 * 1024;
    
    /** 自动重试的最大次数 **/
    private static final int DEF_RETRY_COUNT = 3;
    
    /** User Agent **/
    private static final String USER_AGENT = String.format("CFuture-Team/(chenyoca) Ver %s ",VERSION);
    
    /** 默认的异常重试处理 **/
    public static class DefaultRetryHandler implements HttpRequestRetryHandler {

    	@Override
    	public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
    		if (executionCount >= DEF_RETRY_COUNT) {
    			return false;
    		}
    		if (exception instanceof NoHttpResponseException) {
    			return true;
    		}
    		if (exception instanceof SSLHandshakeException) {
    			return false;
    		}
    		HttpRequest request = (HttpRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
    		boolean idempotent = (request instanceof HttpEntityEnclosingRequest);
    		if (!idempotent) {
    			return true;
    		}
    		return false;
    	}

    }
    
    /** 是否允许重定向到同一个地址 **/
	private boolean mAllowCircleRedirects = false;
	
	/** Socket超时 **/
	private int mSocketTimeOut = DEF_SOCKET_TIMEOUT;
	
	/** 每个路由节点最大的连接数 **/
	private int mMaxConnectionsPerRoute = DEF_MAX_CONNECTIONS_PER_ROUTE;
	
	/** 最大连接数 **/
	private int mMaxConnections = DEF_MAX_CONNECTIONS;
	
	/** 请求拦截器 **/
	private HttpRequestInterceptor mHttpRequestInterceptor;
	
	/** 响应拦截器 **/
	private HttpResponseInterceptor mHttpResponseInterceptor;
	
	/** 异常重试处理接口**/
	private HttpRequestRetryHandler mHttpRequestRetryHandler;
	
	public HttpClientSetting(){
		mHttpRequestRetryHandler = new DefaultRetryHandler();
	}
	
	/**
	 * 创建一个默认的HttpParams对象
	 * @return HttpParams对象
	 */
	public BasicHttpParams buildDefaultHttpParams(){
    	
    	BasicHttpParams httpParams = new BasicHttpParams();
		HttpConnectionParams.setSoTimeout(httpParams, mSocketTimeOut);
		HttpConnectionParams.setConnectionTimeout(httpParams, mSocketTimeOut);
		HttpConnectionParams.setTcpNoDelay(httpParams, true);
		HttpConnectionParams.setSocketBufferSize(httpParams, DEF_SOCKET_BUFFER_SIZE);
		
        httpParams.setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, mAllowCircleRedirects);
        httpParams.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
        
        ConnManagerParams.setTimeout(httpParams, mSocketTimeOut);
        ConnManagerParams.setMaxConnectionsPerRoute(httpParams, new ConnPerRouteBean(mMaxConnectionsPerRoute));
        ConnManagerParams.setMaxTotalConnections(httpParams, mMaxConnections);
        
        HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setUserAgent(httpParams, USER_AGENT);
       
    	return httpParams;
    }
	
	/**
	 * @param allowCircleRedirects the mAllowCircleRedirects to set
	 */
	public HttpClientSetting setAllowCircleRedirects(boolean allowCircleRedirects) {
		this.mAllowCircleRedirects = allowCircleRedirects;
		return this;
	}

	/**
	 * @param mSocketTimeOut the mSocketTimeOut to set
	 */
	public HttpClientSetting setSocketTimeOut(int mSocketTimeOut) {
		this.mSocketTimeOut = mSocketTimeOut;
		return this;
	}

	/**
	 * @param maxConnectionsPerRoute the mMaxConnectionsPerRoute to set
	 */
	public HttpClientSetting setMaxConnectionsPerRoute(int maxConnectionsPerRoute) {
		this.mMaxConnectionsPerRoute = maxConnectionsPerRoute;
		return this;
	}

	/**
	 * @param maxConnections the mMaxConnections to set
	 */
	public HttpClientSetting setMaxConnections(int maxConnections) {
		this.mMaxConnections = maxConnections;
		return this;
	}

	/**
	 * @return the mHttpRequestInterceptor
	 */
	public HttpRequestInterceptor getHttpRequestInterceptor() {
		return mHttpRequestInterceptor;
	}

	/**
	 * @param mttpRequestInterceptor the mHttpRequestInterceptor to set
	 */
	public void setHttpRequestInterceptor(
			HttpRequestInterceptor mttpRequestInterceptor) {
		this.mHttpRequestInterceptor = mttpRequestInterceptor;
	}

	/**
	 * @return the mHttpResponseInterceptor
	 */
	public HttpResponseInterceptor getHttpResponseInterceptor() {
		return mHttpResponseInterceptor;
	}

	/**
	 * @param httpResponseInterceptor the mHttpResponseInterceptor to set
	 */
	public void setHttpResponseInterceptor(
			HttpResponseInterceptor httpResponseInterceptor) {
		this.mHttpResponseInterceptor = httpResponseInterceptor;
	}

	/**
	 * @return the mHttpRequestRetryHandler
	 */
	public HttpRequestRetryHandler getHttpRequestRetryHandler() {
		return mHttpRequestRetryHandler;
	}

	/**
	 * @param httpRequestRetryHandler the mHttpRequestRetryHandler to set
	 */
	public HttpClientSetting setHttpRequestRetryHandler(
			HttpRequestRetryHandler httpRequestRetryHandler) {
		this.mHttpRequestRetryHandler = httpRequestRetryHandler;
		return this;
	}
}
